Skip to content

feat(ui): rework the settings drawers, plugin panel and add-model list - #700

Merged
gloryfromca merged 2 commits into
mainfrom
feat/settings_drawer_redesign
Sep 23, 2026
Merged

gloryfromca merged 2 commits into
mainfrom
feat/settings_drawer_redesign

Conversation

@arelchan

Copy link
Copy Markdown
Contributor

Summary

A pass over the settings dialog's drawers, the plugin page and the model
provider page, plus one composer layout fix. Frontend only: no RPC or
backend change.

Row drawers (tools, plugins, chat parameters). A drawer is the same
table indented one step and tied to its row by a rail, instead of a bordered
card inside the card. Its controls line up with the row's own control edge
and are one size (28px / 12px). The old rule that claimed this step down
never applied: it named .settings-mini, a class no markup carries, so it
and eight sibling rules were dead and are removed. The chat parameters
disclose through the page's own fold (.foldcap) and read out their values
while closed; the context window's value and mode share one row. An open row
gives up its separator (opening one used to make a line appear between the
row and its own drawer, because the row stopped being :last-child). The
add-a-provider box keeps its box on rules scoped to both classes, which it
previously lost to the drawer's later, equal-specificity rules.

Plugins. The drawer now shows what the runtime row and the catalogue
entry already carried and the page dropped: the credential, the address,
the tool names, and the connection manager's own error text. A server the
catalogue has no entry for is no longer told "this server takes no
credential" (github hit this with an expired token); the offline fixture's
catalogue ids and auth modes now match its rows. "Connection failed" is a
static status chip; reconnect moved into the drawer, first, beside the
reason.

Model providers.

  • The add-model popover lists only models not yet added, is tick-then-add
    (one model.add_models call for the ticked set), and has a select-all per
    vendor group and one for everything shown. Previously each click wrote one
    model and reloaded every configured provider twice.
  • Rows and chips name a model without the provider's own prefix (full id in
    the title), and a gateway's live list groups by vendor rather than under
    the gateway's own name.
  • The configured-model chips fold past eight; the fold state lives in the
    store so a removal does not collapse it.
  • One outbound link per page (the name's arrow opened the same key page as
    "Get a key"). Fields are one width with their buttons on the pane's right
    edge. A keyless local provider no longer shows "Server address" twice.
  • Controls inside a section label no longer inherit its bold (the "Add
    model" button was weight 600).

Composer. dockLift measures every direct child of the dock rather than
a class list, so the running-task chip moves the transcript up instead of
covering its last lines.

Copy: gui.settings.roles.chat_use now says it is the default configuration
for new sessions. Unused keys (ctx_current, plugins.auth,
plugins.failed_retry, model.add_all, model.add_group,
providers.showing_added) are removed and the TUI catalogue regenerated.

Type

  • Fix
  • Feature
  • Docs
  • CI / tooling
  • Refactor
  • Other

Verification

Run on the branch after rebasing onto main (5b3788d):

  • npm run gen:check --prefix ui-web: generated.ts matches the contract
  • npm run type-check --prefix ui-web: clean
  • npm run lint --prefix ui-web: 0 errors (4 pre-existing warnings in other files)
  • npm test --prefix ui-web: 206 files, 2854 tests passed
  • npm run lint:i18n --prefix ui-tui: generated catalogue is up to date

New tests: scripts/gates/settings-drawer-css.test.mjs (stylesheet facts
jsdom cannot see, including that every .settings-cfg .X rule targets a
class the markup carries), features/composer/store.dockLift.test.ts (stubs
rects and asserts the measured value), and cases in Roles.test.tsx,
Plugins.test.tsx, ProviderDetail.test.tsx. Each new assertion was
mutation-checked: the change was reverted in place and the test failed.

Checked in a real browser against the offline fixtures and against a live
local gateway (settings read, models ticked but never added): widths,
alignment, weights and tick latency (30-46 ms, no RPC per tick) measured
with getComputedStyle / getBoundingClientRect.

  • Relevant tests pass locally
  • Relevant lint / type checks pass locally
  • User-facing docs or screenshots are updated when needed

No user docs describe these screens.

Risk

  • Security impact considered
  • Backward compatibility considered
  • Rollback path is clear for risky changes

User-visible: the add-model popover no longer removes models (the chips'
x on the provider page does, with the same in-use refusal), and a click on
a row ticks instead of writing. No stored data or wire shape changes; the
settings source's serverAuthFields became serverDetail inside the page
only. Rollback is reverting this commit.

Related Issues

N/A

arelchan and others added 2 commits September 23, 2026 14:33
Settings drawers
- The row drawer is the same table indented one step and tied to its row
  by a rail, not a card inside a card. Controls line up with the row's own
  control edge and are one size (28px, 12px), which the old rule claimed
  but never applied: it named `.settings-mini`, a class no markup carries.
- The chat role's parameters disclose through the page's own fold and read
  out their values while closed; the window's value and mode share a row.
- An open row gives up its separator instead of growing one between itself
  and its drawer. The add-a-provider box keeps its box on its own rules.
- Controls in a section label no longer inherit the label's bold.

Plugins
- The drawer shows what the runtime row and the catalogue already carry:
  the credential, the address, the tools, and the manager's own error.
- A server the catalogue has no entry for is no longer told it needs no
  credential; the offline catalogue ids and auth modes now match the rows.
- "Connection failed" is a status chip; reconnect lives in the drawer,
  first, beside the reason.

Model providers
- The add-model list offers only what is not added yet, is ticked and then
  added in one call, and has a select-all per vendor and for what is shown.
  Ticking no longer writes and reloads every provider per click.
- Rows and chips name a model without the provider's own prefix, and a
  gateway's list groups by vendor instead of under the gateway's name.
- The model chips fold past eight; the fold survives a removal.
- One outbound link per page; fields are one width with their buttons on
  the pane's right edge; a keyless local server asks for its address once.

Composer
- The dock lift counts every docked child, so the running-task chip moves
  the transcript up instead of covering its tail.

Co-authored-by: Claude (claude-opus-5-5) <noreply@anthropic.com>
Co-authored-by: Claude (claude-opus-5-5) <noreply@anthropic.com>

@gloryfromca gloryfromca left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blockers; this can merge as far as I am concerned.

Reviewed the complete github/main...HEAD change and the final one-line delta to 3901e2942115. I covered the repository rules and Web UI vocabulary, the diff and relevant history, settings/source/store callers, RPC and fixture shapes, state transitions, backward compatibility, test changes, and the Web UI architecture boundaries. I found no weakened tests or concrete regression worth raising.

Verification:

  • affected Vitest files: 99 passed
  • full Vitest run: 2853 passed, 1 unrelated session-registry test timed out; isolated rerun passed 28/28
  • uv run pytest tests/test_rpc_model.py tests/test_rpc_plughub.py -x: 249 passed
  • TypeScript type-check: passed
  • ESLint: passed with 4 existing warnings in untouched files
  • production build and generated-client check: passed
  • source-language and large-file gates: passed

@arelchan
arelchan requested a review from 0xKT September 23, 2026 06:53
@gloryfromca
gloryfromca merged commit b63560c into main Sep 23, 2026
23 checks passed
@gloryfromca
gloryfromca deleted the feat/settings_drawer_redesign branch September 23, 2026 06:54
LivXue pushed a commit that referenced this pull request Oct 12, 2026
#700)

## Summary

A pass over the settings dialog's drawers, the plugin page and the model
provider page, plus one composer layout fix. Frontend only: no RPC or
backend change.

**Row drawers (tools, plugins, chat parameters).** A drawer is the same
table indented one step and tied to its row by a rail, instead of a
bordered
card inside the card. Its controls line up with the row's own control
edge
and are one size (28px / 12px). The old rule that claimed this step down
never applied: it named `.settings-mini`, a class no markup carries, so
it
and eight sibling rules were dead and are removed. The chat parameters
disclose through the page's own fold (`.foldcap`) and read out their
values
while closed; the context window's value and mode share one row. An open
row
gives up its separator (opening one used to make a line appear between
the
row and its own drawer, because the row stopped being `:last-child`).
The
add-a-provider box keeps its box on rules scoped to both classes, which
it
previously lost to the drawer's later, equal-specificity rules.

**Plugins.** The drawer now shows what the runtime row and the catalogue
entry already carried and the page dropped: the credential, the address,
the tool names, and the connection manager's own error text. A server
the
catalogue has no entry for is no longer told "this server takes no
credential" (github hit this with an expired token); the offline
fixture's
catalogue ids and auth modes now match its rows. "Connection failed" is
a
static status chip; reconnect moved into the drawer, first, beside the
reason.

**Model providers.**
- The add-model popover lists only models not yet added, is
tick-then-add
(one `model.add_models` call for the ticked set), and has a select-all
per
vendor group and one for everything shown. Previously each click wrote
one
  model and reloaded every configured provider twice.
- Rows and chips name a model without the provider's own prefix (full id
in
the title), and a gateway's live list groups by vendor rather than under
  the gateway's own name.
- The configured-model chips fold past eight; the fold state lives in
the
  store so a removal does not collapse it.
- One outbound link per page (the name's arrow opened the same key page
as
"Get a key"). Fields are one width with their buttons on the pane's
right
  edge. A keyless local provider no longer shows "Server address" twice.
- Controls inside a section label no longer inherit its bold (the "Add
  model" button was weight 600).

**Composer.** `dockLift` measures every direct child of the dock rather
than
a class list, so the running-task chip moves the transcript up instead
of
covering its last lines.

Copy: `gui.settings.roles.chat_use` now says it is the default
configuration
for new sessions. Unused keys (`ctx_current`, `plugins.auth`,
`plugins.failed_retry`, `model.add_all`, `model.add_group`,
`providers.showing_added`) are removed and the TUI catalogue
regenerated.

## Type

- [ ] Fix
- [x] Feature
- [ ] Docs
- [ ] CI / tooling
- [ ] Refactor
- [ ] Other

## Verification

Run on the branch after rebasing onto `main` (5b3788d):

- `npm run gen:check --prefix ui-web`: generated.ts matches the contract
- `npm run type-check --prefix ui-web`: clean
- `npm run lint --prefix ui-web`: 0 errors (4 pre-existing warnings in
other files)
- `npm test --prefix ui-web`: 206 files, 2854 tests passed
- `npm run lint:i18n --prefix ui-tui`: generated catalogue is up to date

New tests: `scripts/gates/settings-drawer-css.test.mjs` (stylesheet
facts
jsdom cannot see, including that every `.settings-cfg .X` rule targets a
class the markup carries), `features/composer/store.dockLift.test.ts`
(stubs
rects and asserts the measured value), and cases in `Roles.test.tsx`,
`Plugins.test.tsx`, `ProviderDetail.test.tsx`. Each new assertion was
mutation-checked: the change was reverted in place and the test failed.

Checked in a real browser against the offline fixtures and against a
live
local gateway (settings read, models ticked but never added): widths,
alignment, weights and tick latency (30-46 ms, no RPC per tick) measured
with `getComputedStyle` / `getBoundingClientRect`.

- [x] Relevant tests pass locally
- [x] Relevant lint / type checks pass locally
- [ ] User-facing docs or screenshots are updated when needed

No user docs describe these screens.

## Risk

- [x] Security impact considered
- [x] Backward compatibility considered
- [x] Rollback path is clear for risky changes

User-visible: the add-model popover no longer removes models (the chips'
`x` on the provider page does, with the same in-use refusal), and a
click on
a row ticks instead of writing. No stored data or wire shape changes;
the
settings source's `serverAuthFields` became `serverDetail` inside the
page
only. Rollback is reverting this commit.

## Related Issues

N/A

---------

Co-authored-by: arelchan <204152633+arelchan@users.noreply.github.com>
Co-authored-by: Claude (claude-opus-5-5) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants